/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * Global Trust Authority is licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

use std::collections::{HashMap};
use serde_cbor;
use ascend_npu_attester::attester::AscendNpuPlugin;
use ascend_npu_attester::config::AscendNpuConfig;
use ascend_npu_attester::entity::{AscendNpuEvidence, DcmiEvidence, DcmiPcrs, DcmiQuote};
use plugin_manager::{PluginError};


#[test]
fn test_config_from_json() {
    let config_json = r#"{
        "enable_boot_measurements": true,
        "enable_runtime_measurements": false,
        "ascend_sdk_path": "/path/to/sdk"
    }"#;
    
    let config = AscendNpuConfig::from_json("ascend_npu".to_string(), config_json).unwrap();
    assert_eq!(config.attester_type, "ascend_npu");
    assert_eq!(config.enable_boot_measurements, true);
    assert_eq!(config.enable_runtime_measurements, false);
    assert_eq!(config.ascend_sdk_path, "/path/to/sdk");
    
    let minimal_json = r#"{}"#;
    let minimal_config = AscendNpuConfig::from_json("ascend_npu".to_string(), minimal_json).unwrap();
    assert_eq!(minimal_config.enable_boot_measurements, false);
    assert_eq!(minimal_config.enable_runtime_measurements, false);
    assert_eq!(minimal_config.ascend_sdk_path, "");
    
    let invalid_json = r#"{invalid json}"#;
    let result = AscendNpuConfig::from_json("ascend_npu".to_string(), invalid_json);
    assert!(result.is_err());
}

#[test]
fn test_evidence_conversion() {
    let mut pcr_map = HashMap::new();
    pcr_map.insert("0".to_string(), b"value0".to_vec());
    pcr_map.insert("1".to_string(), b"value1".to_vec());
    
    let dcmi_evidence = DcmiEvidence {
        ak_cert: b"test_ak_cert".to_vec(),
        quote: DcmiQuote {
            data: b"test_quote_data".to_vec(),
            signature: b"test_quote_signature".to_vec(),
            pcrs: DcmiPcrs {
                hash_alg: "SHA256".to_string(),
                values: pcr_map,
            },
        },
        boot_measurements: b"test_boot_measurements".to_vec(),
        runtime_measurements: b"test_runtime_measurements".to_vec(),
    };
    let ascend_evidence = AscendNpuEvidence::try_from(dcmi_evidence).unwrap();
    assert_eq!(ascend_evidence.ak_cert, "dGVzdF9ha19jZXJ0");
    assert_eq!(ascend_evidence.quote.quote_data, "dGVzdF9xdW90ZV9kYXRh");
    assert_eq!(ascend_evidence.quote.signature, "dGVzdF9xdW90ZV9zaWduYXR1cmU=");
    assert_eq!(ascend_evidence.pcrs.hash_alg, "SHA256");
    assert_eq!(ascend_evidence.pcrs.pcr_values.len(), 2);
    assert_eq!(ascend_evidence.logs.len(), 2);
    
    let pcr0 = ascend_evidence.pcrs.pcr_values.iter().find(|p| p.pcr_index == 0).unwrap();
    assert_eq!(pcr0.pcr_value, hex::encode("value0"));
    
    let pcr1 = ascend_evidence.pcrs.pcr_values.iter().find(|p| p.pcr_index == 1).unwrap();
    assert_eq!(pcr1.pcr_value, hex::encode("value1"));
}

#[test]
fn test_plugin_creation() {
    let query_configuration = |_plugin_type: String| -> Option<String> {
        let config_json = r#"{
            "enable_boot_measurements": true,
            "enable_runtime_measurements": true,
            "ascend_sdk_path": "/path/to/mock/sdk"
        }"#;
        Some(config_json.to_string())
    };
    let result = AscendNpuPlugin::new("ascend_npu".to_string(), query_configuration);
    assert!(result.is_err());
}

#[test]
fn test_error_cases() {
    let query_configuration = |_plugin_type: String| -> Option<String> {
        let config_json = "{}";
        Some(config_json.to_string())
    };
    let result = AscendNpuPlugin::new("wrong_type".to_string(), query_configuration);
    
    assert!(result.is_err());
    match result.unwrap_err() {
        PluginError::InputError(msg) => assert!(msg.contains("Plugin type")),
        _ => panic!("Expected InputError for wrong plugin type"),
    }
    
    let no_config_query = |_plugin_type: String| None;
    let no_config_result = AscendNpuPlugin::new("ascend_npu".to_string(), no_config_query);
    
    assert!(no_config_result.is_err());
    match no_config_result.unwrap_err() {
        PluginError::InputError(msg) => assert!(msg.contains("Failed to query configuration")),
        _ => panic!("Expected InputError for missing configuration"),
    }
}

#[test]
fn test_dcmi_pcrs_deserialization() {
    let mut pcr_map = HashMap::new();
    pcr_map.insert("0".to_string(), b"value0".to_vec());
    
    let dcmi_pcrs = DcmiPcrs {
        hash_alg: "SHA256".to_string(),
        values: pcr_map,
    };
    let serialized = serde_cbor::to_vec(&dcmi_pcrs).unwrap();
    let dcmi_pcrs: DcmiPcrs = serde_cbor::from_slice(&serialized).expect("deserialization failed");
    assert_eq!(dcmi_pcrs.hash_alg, "SHA256");
}